package com.yueyang.sojourn.server.service;

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.yueyang.sojourn.server.common.baymax.web.result.JAssert;
import com.yueyang.sojourn.server.config.QiniuProperties;
import com.yueyang.sojourn.server.model.enums.StatusEnum;
import com.yueyang.sojourn.server.model.po.AttachDetail;
import com.yueyang.sojourn.server.model.vo.UploadResult;
import com.yueyang.sojourn.server.service.attachdetail.AttachDetailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;

/**
 * @author yemingxing
 * @summary
 * @Copyright (c) 2020, Yueyang Group All Rights Reserved.
 * @since 2020-02-24 12:39
 */
@Service
@Slf4j
public class FileService {

    @Resource
    private QiniuProperties qiniuProperties;

    @Autowired
    private UploadManager uploadManager;

    @Autowired
    private AttachDetailService attachDetailService;

    private RestTemplate restTemplate;

    FileService() {
        this.restTemplate = new RestTemplate();
    }

    public File getFile(String fileName) {
        String tempFilePath = System.getProperty("java.io.tmpdir") + "/" + System.currentTimeMillis() + fileName;
        File file = new File(tempFilePath);
        String url = qiniuProperties.getDomain() + "/" + fileName;
        byte[] bytes = restTemplate.getForEntity(url, byte[].class).getBody();

        try {
            FileOutputStream fos = new FileOutputStream(tempFilePath);
            fos.write(bytes);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return file;
    }

    /**
     * 获取上传凭证
     *
     * @param accessKey
     * @param secretKey
     * @param bucket
     * @param fileName
     * @return
     */
    public String getUpToken(String accessKey, String secretKey, String bucket, String fileName) {
        Auth auth = Auth.create(accessKey, secretKey);
        return auth.uploadToken(bucket, StringUtils.defaultIfBlank(fileName, null));
    }

    /**
     * 上传文件（不带上传凭证）
     *
     * @param loginUserId
     * @param accessKey
     * @param secretKey
     * @param bucket
     * @param data
     * @param fileName
     */
    public UploadResult upload(long loginUserId, String accessKey, String secretKey, String bucket, byte[] data, String fileName) {
        Auth auth = Auth.create(accessKey, secretKey);
        String token = auth.uploadToken(bucket, StringUtils.defaultIfBlank(fileName, null));
        DefaultPutRet putRet = qiniuUpload(token, data, fileName);
        return afterPutRet(loginUserId, putRet);
    }

    private UploadResult afterPutRet(long loginUserId, DefaultPutRet putRet) {
        insertAttachDetail(loginUserId, qiniuProperties.getStorage().getBucket(), putRet);
        return formatUploadResult(Objects.requireNonNull(putRet));
    }

    public UploadResult upload(long loginUserId, byte[] data, String fileName) {
        return this.upload(loginUserId, qiniuProperties.getStorage().getAccessKey(), qiniuProperties.getStorage().getSecretKey(), qiniuProperties.getStorage().getBucket(), data, fileName);
    }

    public UploadResult upload(long loginUserId, File file, String fileName) {
        Auth auth = Auth.create(qiniuProperties.getStorage().getAccessKey(), qiniuProperties.getStorage().getSecretKey());
        String token = auth.uploadToken(qiniuProperties.getStorage().getBucket(), StringUtils.defaultIfBlank(fileName, null));
        DefaultPutRet putRet = qiniuUpload(token, file, fileName);
        return afterPutRet(loginUserId, putRet);
    }

    /**
     * 上传文件（带上传凭证）
     *
     * @param loginUserId
     * @param token
     * @param data
     * @param fileName
     */
    public UploadResult upload(long loginUserId, String token, byte[] data, String fileName) {
        DefaultPutRet putRet = qiniuUpload(token, data, fileName);
        return afterPutRet(loginUserId, putRet);
    }

    private UploadResult formatUploadResult(DefaultPutRet putRet) {
        return new UploadResult(qiniuProperties.getDomain(), putRet.key);
    }

    private DefaultPutRet qiniuUpload(String token, byte[] data, String fileName) {
        if (StringUtils.isBlank(fileName)) {
            fileName = RandomStringUtils.randomAlphabetic(16);
        }
        try {
            Response response = uploadManager.put(data, fileName, token);
            //解析上传成功的结果
            return new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        } catch (QiniuException ex) {
            Response r = ex.response;
            log.error(r.toString());
            JAssert.justFailed(r.toString());
            try {
                log.error(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
            return null;
        }
    }

    private DefaultPutRet qiniuUpload(String token, File file, String fileName) {
        if (StringUtils.isBlank(fileName)) {
            fileName = RandomStringUtils.randomAlphabetic(16);
        }
        try {
            Response response = uploadManager.put(file, fileName, token);
            //解析上传成功的结果
            return new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        } catch (QiniuException ex) {
            Response r = ex.response;
            log.error(r.toString());
            JAssert.justFailed(r.toString());
            try {
                log.error(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
            return null;
        }
    }

    private void insertAttachDetail(long creator, String bucket, DefaultPutRet putRet) {
        if (Objects.isNull(putRet)) {
            return;
        }
        AttachDetail attachDetail = new AttachDetail();
        attachDetail.setBucket(bucket);
        attachDetail.setFileKey(putRet.hash);
        attachDetail.setName(putRet.key);
        attachDetail.setStatus(StatusEnum.VALID.getCode());
        attachDetail.setCreator(creator);
        attachDetail.setCreatedTime(new Date());
        attachDetailService.insert(attachDetail);
    }
}
